#include <iostream>
#include "string"

// 多态使用时，如果子类中有属性开辟到堆区，那么父类指针在释放时无法调用到子类的析构代码
// 虚析构和纯虚析构区别：
//      如果是纯虚析构，该类属于抽象类，无法实例化对象

// 虚析构和纯虚析构共性：
// 可以解决父类指针释放子类对象

/*
 * 总结：
    1.虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
    2. 如果子类中没有堆区数据，可以不写为虚析构或纯虚析构
    3.拥有纯虚析构函数的类也属于抽象类
 */
class Animal2 {
public:
    Animal2() {
        std::cout << "Animal2()" << std::endl;
    }

    virtual void speak() = 0;

    // 利用虚析构可以解决，父类指针释放子类对象时不干净的问题
    /*virtual ~Animal2() {
        std::cout << "Animal2析构函数调用" << std::endl;
    }*/

    // 纯虚析构
    virtual ~Animal2() = 0;
};

Animal2::~Animal2() {
    std::cout << "Animal2纯虚析构" << std::endl;
};

class Cat : public Animal2 {
public:
    std::string *name;

    Cat(std::string name) {
        this->name = new std::string(name);
    }

    void speak() override {
        std::cout << *name << "小猫在说话" << std::endl;
    }

    ~Cat() {
        if (name != NULL) {
            std::cout << "Cat析构函数调用" << std::endl;
            delete name;
            name = NULL;
        }
    }
};

void test() {
    Animal2 *animal = new Cat("Tom");
    animal->speak();
    // 父类的指针在析构的时候 不会调用子类中析构函数，导致子类如果有堆区属性，会出现内存泄漏
    delete animal;
}

int main() {

    test();
    return 0;
}

